File indexing completed on 2024-04-21 14:45:04
0001 /* EkosLive Node 0002 0003 SPDX-FileCopyrightText: 2023 Jasem Mutlaq <mutlaqja@ikarustech.com> 0004 0005 Node Manager 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "nodemanager.h" 0011 #include "version.h" 0012 0013 #include <QWebSocket> 0014 #include <QUrlQuery> 0015 #include <QTimer> 0016 #include <QJsonDocument> 0017 0018 #include <KActionCollection> 0019 #include <KLocalizedString> 0020 #include <basedevice.h> 0021 #include <QUuid> 0022 0023 namespace EkosLive 0024 { 0025 0026 /////////////////////////////////////////////////////////////////////////////////////////// 0027 /// 0028 /////////////////////////////////////////////////////////////////////////////////////////// 0029 NodeManager::NodeManager(uint32_t mask) 0030 { 0031 m_NetworkManager = new QNetworkAccessManager(this); 0032 connect(m_NetworkManager, &QNetworkAccessManager::finished, this, &NodeManager::onResult); 0033 0034 // Configure nodes 0035 if (mask & Message) 0036 m_Nodes[Message] = new Node("message"); 0037 if (mask & Media) 0038 m_Nodes[Media] = new Node("media"); 0039 if (mask & Cloud) 0040 m_Nodes[Cloud] = new Node("cloud"); 0041 0042 for (auto &node : m_Nodes) 0043 { 0044 connect(node, &Node::connected, this, &NodeManager::setConnected); 0045 connect(node, &Node::disconnected, this, &NodeManager::setDisconnected); 0046 } 0047 } 0048 0049 /////////////////////////////////////////////////////////////////////////////////////////// 0050 /// 0051 /////////////////////////////////////////////////////////////////////////////////////////// 0052 void NodeManager::setURLs(const QUrl &service, const QUrl &websocket) 0053 { 0054 m_ServiceURL = service; 0055 m_WebsocketURL = websocket; 0056 for (auto &node : m_Nodes) 0057 node->setProperty("url", m_WebsocketURL); 0058 } 0059 0060 /////////////////////////////////////////////////////////////////////////////////////////// 0061 /// 0062 /////////////////////////////////////////////////////////////////////////////////////////// 0063 bool NodeManager::isConnected() const 0064 { 0065 return std::all_of(m_Nodes.begin(), m_Nodes.end(), [](const auto & node) 0066 { 0067 return node->isConnected(); 0068 }); 0069 } 0070 0071 /////////////////////////////////////////////////////////////////////////////////////////// 0072 /// 0073 /////////////////////////////////////////////////////////////////////////////////////////// 0074 void NodeManager::setConnected() 0075 { 0076 auto node = qobject_cast<Node*>(sender()); 0077 if (!node) 0078 return; 0079 0080 auto isConnected = std::all_of(m_Nodes.begin(), m_Nodes.end(), [](const auto & node) 0081 { 0082 return node->isConnected(); 0083 }); 0084 0085 // Only emit once all nodes are connected. 0086 if (isConnected) 0087 emit connected(); 0088 } 0089 0090 /////////////////////////////////////////////////////////////////////////////////////////// 0091 /// 0092 /////////////////////////////////////////////////////////////////////////////////////////// 0093 void NodeManager::setDisconnected() 0094 { 0095 auto node = qobject_cast<Node*>(sender()); 0096 if (!node) 0097 return; 0098 0099 // Only emit once all nodes are disconnected. 0100 if (isConnected() == false) 0101 emit disconnected(); 0102 } 0103 0104 /////////////////////////////////////////////////////////////////////////////////////////// 0105 /// 0106 /////////////////////////////////////////////////////////////////////////////////////////// 0107 void NodeManager::disconnectNodes() 0108 { 0109 for (auto &node : m_Nodes) 0110 node->disconnectServer(); 0111 } 0112 0113 /////////////////////////////////////////////////////////////////////////////////////////// 0114 /// 0115 /////////////////////////////////////////////////////////////////////////////////////////// 0116 void NodeManager::setCredentials(const QString &username, const QString &password) 0117 { 0118 m_Username = username; 0119 m_Password = password; 0120 } 0121 0122 /////////////////////////////////////////////////////////////////////////////////////////// 0123 /// 0124 /////////////////////////////////////////////////////////////////////////////////////////// 0125 void NodeManager::authenticate() 0126 { 0127 QNetworkRequest request; 0128 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); 0129 0130 QUrl authURL(m_ServiceURL); 0131 authURL.setPath("/api/authenticate"); 0132 0133 request.setUrl(authURL); 0134 0135 QJsonObject json = {{"username", m_Username}, {"password", m_Password}}; 0136 0137 auto postData = QJsonDocument(json).toJson(QJsonDocument::Compact); 0138 0139 m_NetworkManager->post(request, postData); 0140 } 0141 0142 /////////////////////////////////////////////////////////////////////////////////////////// 0143 /// 0144 /////////////////////////////////////////////////////////////////////////////////////////// 0145 void NodeManager::onResult(QNetworkReply *reply) 0146 { 0147 if (reply->error() != QNetworkReply::NoError) 0148 { 0149 // If connection refused, retry up to 3 times 0150 if (reply->error() == QNetworkReply::ConnectionRefusedError && m_ReconnectTries++ < RECONNECT_MAX_TRIES) 0151 { 0152 reply->deleteLater(); 0153 QTimer::singleShot(RECONNECT_INTERVAL, this, &NodeManager::authenticate); 0154 return; 0155 } 0156 0157 m_ReconnectTries = 0; 0158 emit authenticationError(i18n("Error authentication with Ekos Live server: %1", reply->errorString())); 0159 reply->deleteLater(); 0160 return; 0161 } 0162 0163 m_ReconnectTries = 0; 0164 QJsonParseError error; 0165 auto response = QJsonDocument::fromJson(reply->readAll(), &error); 0166 0167 if (error.error != QJsonParseError::NoError) 0168 { 0169 emit authenticationError(i18n("Error parsing server response: %1", error.errorString())); 0170 reply->deleteLater(); 0171 return; 0172 } 0173 0174 m_AuthResponse = response.object(); 0175 0176 if (m_AuthResponse["success"].toBool() == false) 0177 { 0178 emit authenticationError(m_AuthResponse["message"].toString()); 0179 reply->deleteLater(); 0180 return; 0181 } 0182 0183 // Cloud only supported for plan_id = 1 0184 if (m_AuthResponse["plan_id"].toString("2") == "2") 0185 m_Nodes.remove(Cloud); 0186 0187 for (auto &node : m_Nodes) 0188 { 0189 node->setAuthResponse(m_AuthResponse); 0190 node->connectServer(); 0191 } 0192 0193 reply->deleteLater(); 0194 } 0195 0196 }