12
sunknown
c_cpp
3 years ago
8.7 kB
6
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...