12

s
 avatar
unknown
c_cpp
3 years ago
8.7 kB
5
Indexable
#include "DxClusterClient.h"
#include <QTcpSocket>
#include <TelnetSocket.h>
#include <QDebug>
#include <QNetworkInterface>

struct DxClusterClient::impl
{

    impl(DxClusterClient &contex) : m_context{contex} {
        m_socket.setSocket(&m_tcpSocket);
        m_timer.setSingleShot(true);

        pCurrent->onEnter();


        QObject::connect(&m_tcpSocket, &QTcpSocket::stateChanged, &m_tcpSocket, [&](QAbstractSocket::SocketState socketStatus) {
            pCurrent->setConnectStatus(socketStatus);
        });

        QObject::connect(&m_socket, &SDR::Telnet_2::message, &m_tcpSocket, [&](const QString &message) {
            pCurrent->setMessage(message);
        });

        connect(&m_timer, &QTimer::timeout, &m_loop, &QEventLoop::quit);
    }

    ~impl() {

    }

    Status status() const {
        return m_status;
    }

    void setStatus(Status status) {
        m_status = status;
    }

    bool checkNetworkConnectivity() {
        bool connectivity = false;
        QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
        for (int i = 0; i < interfaces.count(); i++) {
            QNetworkInterface interface = interfaces.at(i);
            if (interface.flags().testFlag(QNetworkInterface::IsUp)
                    && !interface.flags().testFlag(QNetworkInterface::IsLoopBack)
                    && interface.flags().testFlag(QNetworkInterface::IsRunning))
            {
                connectivity = true;
            }
        }
        qDebug() << "Connectivity" << connectivity;
        return connectivity;
    }

    void connectToHost(const QString &callsign, const QString &host, quint16 port) {
        pCurrent->connectToHost(callsign, host, port);


    }

    void authorization(const QString &callsign){
        qDebug() << "Authorization!!!";

        setStatus(Status::Authorization);

        while (m_context.status() == Status::Authorization) {
            if (checkNetworkConnectivity()) {
                if (m_status != Status::Authorized) {
                    m_socket.sendData(callsign);
                }

                setStatus(Status::Authorized);
            } else {
                close();
            }
        }

        serverListening();
    }

    void serverListening()
    {
        while (m_context.status() == Status::Authorized) {

            qDebug() << "listening";

            m_timer.start(30000);
            m_loop.exec();

            if (!checkNetworkConnectivity()) {
                qDebug() << "disconnecting";
                setStatus(Status::Disconnecting);
                close();
            }
        }
    }

    void close() {
        m_socket.close();

        if (m_tcpSocket.waitForDisconnected(5000)) {
            qDebug() << "disconnected";
            setStatus(Status::Disconnected);
        }
    }

private:
    struct state_t {
        state_t(){}
        virtual ~state_t(){}
        virtual void onEnter(){}
        virtual void onExit(){}
        virtual void connectToHost(const QString &callsign, const QString &host, quint16 port){}
        virtual void close(){}
        virtual void setConnectStatus(QAbstractSocket::SocketState socketStatus){}
        virtual void setMessage(const QString &message){}
    };

    struct idle_t : state_t {
        idle_t(impl &context) : m_context{context} {}

        void connectToHost(const QString &callsign, const QString &host, quint16 port) override {
            m_context.m_callsign = callsign;
            m_context.m_host = host;
            m_context.m_port = port;

            m_context.switchState(m_context.m_connecting);
        }

    private:
        impl &m_context;
    };

    struct connecting_t : state_t {
        connecting_t(impl &context) : m_context{context} {}

        void onEnter() override {
            emit m_context.m_context.statusChanged(Status::Connecting);

            m_context.m_socket.connectToHost(m_context.m_host, m_context.m_port);

            m_context.m_timer.start(5000);
            m_context.m_loop.exec();

            if (m_context.m_tcpSocket.state() == m_context.m_tcpSocket.ConnectedState) {
                //setStatus(Status::Connected);
                //authorization(callsign);
                qDebug() << "connected";
            }
        }

        void setConnectStatus(QAbstractSocket::SocketState socketStatus) override{
            if (socketStatus == QAbstractSocket::SocketState::ConnectedState) {
                m_context.switchState(m_context.m_authorizing);
            } else if ((QAbstractSocket::SocketState::UnconnectedState) || (QAbstractSocket::SocketState::ClosingState)) {
                m_context.switchState(m_context.m_reconnecting);
            }
        }

        void close() override{
            m_context.switchState(m_context.m_idle);
            m_context.m_socket.close();
        }

        void onExit() override {

        }

    private:
        impl &m_context;
    };

    struct authorizing_t : state_t {
        authorizing_t(impl &context) : m_context{context}{

        }
        void onEnter() override {

        }

        void setMessage(const QString &message) override{
            if (isSetCallsign(message)) {

            } else if (isAuthorized(message)) {

            } else if (isError(message)) {

            } else {

            }
        }

        void setConnectStatus(QAbstractSocket::SocketState socketStatus) override{
           if ((QAbstractSocket::SocketState::UnconnectedState) || (QAbstractSocket::SocketState::ClosingState)) {
                m_context.switchState(m_context.m_reconnecting);
            }
        }

        void close() override{
            m_context.switchState(m_context.m_idle);
            m_context.m_socket.close();
        }

        void onExit() override {

        }

    private:
        bool isSetCallsign(const QString &text) const {
            return false;
        }

        bool isAuthorized(const QString &text) const {
            return false;
        }

        bool isError(const QString &text) const {
            return false;
        }

    private:
        impl &m_context;
    };

    struct process_t : state_t {
        process_t(impl &context) : m_context{context}{

        }
        void onEnter() override {

        }

        void close() override{
            m_context.switchState(m_context.m_idle);
            m_context.m_socket.close();
        }

        void onExit() override {

        }
    private:
        impl &m_context;
    };

    struct reconnect_t : state_t {
        reconnect_t(impl &context) : m_context{context}{
            QObject::connect(&m_timer, &QTimer::timeout, &m_timer, [&](){
                m_context.switchState(m_context.m_connecting);
            });
        }
        void onEnter() override {
            m_timer.start(1000);
        }
        void onExit() override {
            m_timer.stop();
        }

        void setConnectStatus(QAbstractSocket::SocketState socketStatus) {
           if ((QAbstractSocket::SocketState::UnconnectedState) || (QAbstractSocket::SocketState::ClosingState)) {
                m_context.switchState(m_context.m_reconnecting);
            }
        }

        void close() override{
            m_context.switchState(m_context.m_idle);
            m_context.m_socket.close();
        }

    private:
        impl &m_context;
        QTimer m_timer;
    };

    void switchState(state_t &state) {
        if (pCurrent != &state) {
            pCurrent->onExit();
            pCurrent = &state;
            pCurrent->onEnter();
        }
    }

private:
    DxClusterClient &m_context;
    QTcpSocket m_tcpSocket;
    SDR::Telnet_2 m_socket;
    Status m_status = Status::Disconnected;
    QTimer m_timer;
    QEventLoop m_loop;

    QString m_callsign {};
    QString m_host {};
    quint16 m_port {};

    idle_t m_idle {*this};
    connecting_t m_connecting {*this};
    authorizing_t m_authorizing {*this};
    process_t m_process {*this};
    reconnect_t m_reconnecting {*this};
    state_t *pCurrent {&m_idle};
};



DxClusterClient::DxClusterClient(QObject *parent)
    : QObject{parent},
      pImpl{std::make_unique<impl>(*this)}
{

}

DxClusterClient::~DxClusterClient()
{

}

DxClusterClient::Status DxClusterClient::status() const
{
    return pImpl->status();
}

void DxClusterClient::connectToHost(const QString &callsign, const QString &host, quint16 port)
{
    pImpl->connectToHost(callsign, host, port);
}

void DxClusterClient::authorization(const QString &callsign)
{
    pImpl->authorization(callsign);
}

void DxClusterClient::serverListening()
{
    pImpl->serverListening();
}

void DxClusterClient::close()
{
    pImpl->close();
}
Editor is loading...