#pragma once #include #include #include #include #include "JDefines.h" #include "JSys.h" #include "JTerminal.h" #include "JExtTerminal.h" #include "JConfig.h" #include "WebTerminalCommands.h" #include "WebSocketTerminalFrame.h" #include "WebSocketTerminalServiceCommand.h" #include "WebSocketTerminalHelpCommand.h" namespace Incart::Net::WebSockets { class WebSocketTerminal : public QObject, public Common::JExtTerminal { Q_OBJECT const bool MYDEBUG = true; protected: bool m_flgConnection = false; QWebSocketServer m_pWebSocketServer; std::unordered_map m_clients; WebSocketTerminalFrame m_frame; std::vector> m_serviceCommands; public: WebSocketTerminal(quint16 port, QObject *parent = nullptr) : QObject(parent) , m_pWebSocketServer("WebSocketServer",QWebSocketServer::NonSecureMode, this) { Common::JT() << __PRETTY_FUNCTION__; m_serviceCommands.push_back(std::make_shared("Help")); if (m_pWebSocketServer.listen(QHostAddress::Any, port)) { Common::JTerminal(JCL_GREEN) << __PRETTY_FUNCTION__ << "listen ..." << port << m_pWebSocketServer.serverUrl(); connect(&m_pWebSocketServer, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); connect(&m_pWebSocketServer, &QWebSocketServer::closed, this, &WebSocketTerminal::slotClosed); } else { Common::JTerminal(JCL_YELLOW) << __PRETTY_FUNCTION__ << "listen error" << port; } } ~WebSocketTerminal() override { Common::JT() << __PRETTY_FUNCTION__; allDisconnected(); // разрываем каналы связи } void out(char color, char* time, char* messageType, char* message) override { QByteArray frame = m_frame.exe(color, time, messageType, message); out(frame.data()); } void out(const char* message) { if (!m_flgConnection) return; for (auto it = m_clients.begin(); it != m_clients.end(); it++) { it->first->sendTextMessage(message); } } signals: void signalConnection(); void signalDisConnection(); void signalError(const std::string& errorType, const std::string& message); // void signalExit(); public slots: void slotDeviceConnect() { std::cout << __PRETTY_FUNCTION__ << std::endl; } void slotDeviceDisconnect() { } void slotClosed() { Common::JTerminal(JCL_RED) << __PRETTY_FUNCTION__; //!! я не знаю, когда это возникает } void slotNewConnection() { QWebSocket* client = m_pWebSocketServer.nextPendingConnection(); m_clients[client] = false; Common::JTerminal() << __PRETTY_FUNCTION__ << m_clients.size() << client->peerAddress(); connect(client, &QWebSocket::textMessageReceived, this, &WebSocketTerminal::slotMessageReceived); connect(client, &QWebSocket::disconnected, this, &WebSocketTerminal::socketDisconnected); if (!m_flgConnection) { m_flgConnection = true; signalConnection(); } } void socketDisconnected() { QWebSocket* client = qobject_cast(sender()); if (client != nullptr) { m_clients.erase(client); client->deleteLater(); Common::JTerminal() << __PRETTY_FUNCTION__ << m_clients.size() << client->peerAddress(); if( m_clients.size() <= 0 ) { m_flgConnection = false; emit signalDisConnection(); Common::JTerminal(JCL_YELLOW) << __PRETTY_FUNCTION__ << "all external terminals are off "; } } } void slotMessageReceived(QString msg) { QWebSocket* client = qobject_cast(sender()); Common::JT() << __PRETTY_FUNCTION__ << client << " " << msg; //client->sendTextMessage(m_kdr.exeInit()); // передаем кадр инициализации m_clients[client] = true; // устанавливаем статус клиента if (msg=="exit") { Common::JSys::exit(); } else if (msg=="?") { Common::JConfig::priRgs(); } } void slotTransfer(QString msg) { //Common::JT() << __PRETTY_FUNCTION__; out(reinterpret_cast(msg.data())); } private: void allDisconnected() { m_pWebSocketServer.close(); for (auto it = m_clients.begin(); it != m_clients.end(); it++) { it->first->deleteLater(); } m_clients.clear(); } char* getTime() { static QString str; static QByteArray buf; str = "[" + QTime::currentTime().toString("hh:mm:ss.zzz") + "]"; buf = str.toLocal8Bit(); return reinterpret_cast(buf.data()); } void out(char color, const char* messageType, const char* message, QWebSocket* client) { QByteArray frame = m_frame.exe(color, getTime(), messageType, message); if (!m_flgConnection) return; client->sendTextMessage(frame.data()); } std::shared_ptr findServiceCommand(const std::string& name) { for (size_t i = 0; i < m_serviceCommands.size(); i++) { if (Common::StringExtensions::isEqualsInsensitive(name, m_serviceCommands[i]->getName())) { return m_serviceCommands[i]; } } return nullptr; } }; } // namespace Incart::Net::WebSockets