qmqtt_pubsubclient.cpp 10.4 KB
/* ****************************************************************************
 * Copyright 2019 Open Systems Development BV                                 *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    *
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        *
 * DEALINGS IN THE SOFTWARE.                                                  *
 * ***************************************************************************/
// osdev::components
#include "qmqtt_pubsubclient.h"
#include "log.h"

// Qt
#include <QRandomGenerator>

using namespace osdev::components;

QMqttPubSubClient::QMqttPubSubClient(const QHostAddress& host,
                                     const quint16 port,
                                     QObject *parent)
    : QMQTT::Client(host, port, parent)
    , m_mqtt_topic()
    , m_current_state(mqtt::E_CLIENT_UNKNOWN)
    , m_subTemp()
    , m_pubTemp()
{
    this->connectSignalsAndSlots();

    this->connectToHost();
}

QMqttPubSubClient::~QMqttPubSubClient()
{

}

void QMqttPubSubClient::subscribe(const QString& message_topic)
{
    if(m_current_state == mqtt::E_CLIENT_CONNECTED)
    {
        QMQTT::Client::subscribe(message_topic);
    }
    else
    {
        m_subTemp.first     = message_topic;
        m_subTemp.second    = QString();
    }
}

void QMqttPubSubClient::unsubscribe(const QString& message_topic)
{
    if(m_current_state == mqtt::E_CLIENT_SUBSCRIBED)
    {
        QMQTT::Client::unsubscribe( message_topic );
    }
}

void QMqttPubSubClient::publish(const QString& message_topic, const QString& message_payload)
{
    if(m_current_state == mqtt::E_CLIENT_CONNECTED ||
       m_current_state == mqtt::E_CLIENT_SUBSCRIBED ||
       m_current_state == mqtt::E_CLIENT_PUBLISHED)
    {
        QMQTT::Message oMessage( QRandomGenerator::global()->generate(),
                                 message_topic,
                                 QByteArray(message_payload.toStdString().c_str()),
                                 0, true, false );
        QMQTT::Client::publish(oMessage);
    }
    else
    {
        m_pubTemp.first     = message_topic;
        m_pubTemp.second    = message_payload;
    }
}

void QMqttPubSubClient::slotOnConnected()
{
    // Ok. We're connected at the moment. Lets set the state and see what we need to do.
    m_current_state = mqtt::E_CLIENT_CONNECTED;

    if(!m_subTemp.first.isEmpty())
    {
        this->subscribe( m_subTemp.first );
    }
    else if(!m_pubTemp.first.isEmpty())
    {
        this->publish( m_pubTemp.first, m_pubTemp.second );
    }
}

void QMqttPubSubClient::slotOnDisconnected()
{
    m_current_state = mqtt::E_CLIENT_DISCONNECTED;
}

void QMqttPubSubClient::slotOnError(const QMQTT::ClientError error)
{
    m_current_state = mqtt::E_CLIENT_ERROR;
    LogError( "[QMqttPubSubClient::slotOnError]", QString( "An error occured : %1" ).arg( error ) );
    LogError( "[QMqttPubSubClient::slotOnError]", this->getErrorMessage( error ) );
}

QString QMqttPubSubClient::getErrorMessage( const QMQTT::ClientError error )
{

    QString l_error_message;

    switch( error )
    {
        case QMQTT::SocketConnectionRefusedError:
            l_error_message = "[Socket] - Connection Refused";
            break;
        case QMQTT::SocketRemoteHostClosedError:
            l_error_message = "[Socket] - Remote Host Closed";
            emit signalReInitialise();
            break;
        case QMQTT::SocketHostNotFoundError:
            l_error_message = "[Socket] - Host Not Found.";
            break;
        case QMQTT::SocketAccessError:
            l_error_message = "[Socket] - Access Error.";
            break;
        case QMQTT::SocketResourceError:
            l_error_message = "[Socket] - Resource Error.";
            break;
        case QMQTT::SocketTimeoutError:
            l_error_message = "[Socket] - Timeout.";
            break;
        case QMQTT::SocketDatagramTooLargeError:
            l_error_message = "[Socket] - Datagram Too Large.";
            break;
        case QMQTT::SocketNetworkError:
            l_error_message = "[Socket] - Network Error.";
            break;
        case QMQTT::SocketAddressInUseError:
            l_error_message = "[Socket] - Address In Use.";
            break;
        case QMQTT::SocketAddressNotAvailableError:
            l_error_message = "[Socket] - Address Not Available.";
            break;
        case QMQTT::SocketUnsupportedSocketOperationError:
            l_error_message = "[Socket] - Unsupported Socket Operation.";
            break;
        case QMQTT::SocketUnfinishedSocketOperationError:
            l_error_message = "[Socket] - Unfinished Socket Operation.";
            break;
        case QMQTT::SocketProxyAuthenticationRequiredError:
            l_error_message = "[Socket] - Proxy Authentication Required.";
            break;
        case QMQTT::SocketSslHandshakeFailedError:
            l_error_message = "[Socket] - SSL Handshake Failed.";
            break;
        case QMQTT::SocketProxyConnectionRefusedError:
            l_error_message = "[Socket] - Proxy Connection Refused.";
            break;
        case QMQTT::SocketProxyConnectionClosedError:
            l_error_message = "[Socket] - Proxy Connection Closed.";
            break;
        case QMQTT::SocketProxyConnectionTimeoutError:
            l_error_message = "[Socket] - Proxy Connection Closed.";
            break;
        case QMQTT::SocketProxyNotFoundError:
            l_error_message = "[Socket] - Proxy Not Found.";
            break;
        case QMQTT::SocketProxyProtocolError:
            l_error_message = "[Socket] - Proxy Protocol Error.";
            break;
        case QMQTT::SocketOperationError:
            l_error_message = "[Socket] - Operation Error.";
            break;
        case QMQTT::SocketSslInternalError:
            l_error_message = "[Socket] - SSL Internal Error.";
            break;
        case QMQTT::SocketSslInvalidUserDataError:
            l_error_message = "[Socket] - SSL Invalid User Data.";
            break;
        case QMQTT::SocketTemporaryError:
            l_error_message = "[Socket] - Temporary Error.";
            break;
        case QMQTT::MqttUnacceptableProtocolVersionError:
            l_error_message = "[MQTT] - Unacceptable Protocol Version.";
            break;
        case QMQTT::MqttIdentifierRejectedError:
            l_error_message = "[MQTT] - Identifier Rejected.";
            break;
        case QMQTT::MqttServerUnavailableError:
            l_error_message = "[MQTT] - Server Unavailable.";
            break;
        case QMQTT::MqttBadUserNameOrPasswordError:
            l_error_message = "[MQTT] - Bad Username Or Password.";
            break;
        case QMQTT::MqttNotAuthorizedError:
            l_error_message = "[MQTT] - Not Authorized.";
            break;
        case QMQTT::MqttNoPingResponse:
            l_error_message = "[MQTT] - No Ping Response";
            break;
        case QMQTT::UnknownError:
        default:
            l_error_message = "An Unknown Error Occurred";
            break;
    }

    return l_error_message;
}

void QMqttPubSubClient::slotOnSubscribed(const QString& topic, const quint8 qos)
{
    Q_UNUSED(qos);
    m_current_state = mqtt::E_CLIENT_SUBSCRIBED;
    LogInfo("[QMqttPubSubClient::slotOnSubscribed]", QString("Subscribed to topic %1").arg(topic));
}

void QMqttPubSubClient::slotOnUnSubscribed(const QString& topic)
{
    m_current_state = mqtt::E_CLIENT_UNSUBSCRIBED;
    LogInfo("[QMqttPubSubClient::slotOnUnSubscribed]", QString("Unsubscribed to topic %1").arg(topic));
}

void QMqttPubSubClient::slotOnPublished(const QMQTT::Message& message, quint16 msgid)
{

    m_current_state = mqtt::E_CLIENT_PUBLISHED;
    LogInfo("[QMqttPubSubClient::slotOnPublished]", QString("Message %1 published to topic %2 with id %3").arg(message.topic()).arg(message.payload().toStdString().c_str()).arg(msgid));
}

void QMqttPubSubClient::slotOnReceived(const QMQTT::Message& message)
{
    LogDebug("[QMqttPubSubClient::slotOnReceived]", QString("Received payload : %1 from topic : %2").arg(message.payload().toStdString().c_str()).arg(message.topic()));
    emit signalMessageReceived(message.topic(), message.payload().toStdString().c_str());
}

void QMqttPubSubClient::slotOnPingResp()
{
    LogDebug("[QMqttPubSubClient::slotOnPingResp]", QString("Ping Response received."));
}

#ifndef QT_NO_SSL
void QMqttPubSubClient::slotSslErrors(const QList<QSslError>& errors)
{
    Q_UNUSED(errors);
}
#endif  /* QT_NO_SSL */

void QMqttPubSubClient::connectSignalsAndSlots()
{
    connect(this, &QMQTT::Client::connected, this, &QMqttPubSubClient::slotOnConnected);
    connect(this, &QMQTT::Client::disconnected, this, &QMqttPubSubClient::slotOnDisconnected);
    connect(this, &QMQTT::Client::error, this, &QMqttPubSubClient::slotOnError);
    connect(this, &QMQTT::Client::subscribed, this, &QMqttPubSubClient::slotOnSubscribed);
    connect(this, &QMQTT::Client::unsubscribed, this, &QMqttPubSubClient::slotOnUnSubscribed);
    connect(this, &QMQTT::Client::published, this, &QMqttPubSubClient::slotOnPublished);
    connect(this, &QMQTT::Client::received, this, &QMqttPubSubClient::slotOnReceived);
    connect(this, &QMQTT::Client::pingresp, this, &QMqttPubSubClient::slotOnPingResp);
#ifndef QT_NO_SSL
    connect(this, &QMQTT::Client::sslErrors, this, &QMqttPubSubClient::slotSslErrors);
#endif  /* QT_NO_SSL */
}