File indexing completed on 2025-02-16 06:40:15
0001 /* 0002 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "clientmanager.h" 0008 0009 #include "deviceinfo.h" 0010 #include "drivermanager.h" 0011 #include "guimanager.h" 0012 #include "indilistener.h" 0013 #include "Options.h" 0014 #include "servermanager.h" 0015 0016 #include <indi_debug.h> 0017 #include <QTimer> 0018 0019 ClientManager::ClientManager() 0020 { 0021 connect(this, &ClientManager::newINDIProperty, this, &ClientManager::processNewProperty, Qt::UniqueConnection); 0022 connect(this, &ClientManager::removeBLOBManager, this, &ClientManager::processRemoveBLOBManager, Qt::UniqueConnection); 0023 } 0024 0025 bool ClientManager::isDriverManaged(const QSharedPointer<DriverInfo> &driver) 0026 { 0027 return std::any_of(m_ManagedDrivers.begin(), m_ManagedDrivers.end(), [driver](const auto & oneDriver) 0028 { 0029 return driver == oneDriver; 0030 }); 0031 } 0032 0033 void ClientManager::newDevice(INDI::BaseDevice dp) 0034 { 0035 //setBLOBMode(B_ALSO, dp->getDeviceName()); 0036 // JM 2018.09.27: ClientManager will no longer handle BLOB, just messages. 0037 // We relay the BLOB handling to BLOB Manager to better manage concurrent connections with large data 0038 setBLOBMode(B_NEVER, dp.getDeviceName()); 0039 0040 if (QString(dp.getDeviceName()).isEmpty()) 0041 { 0042 qCWarning(KSTARS_INDI) << "Received invalid device with empty name! Ignoring the device..."; 0043 return; 0044 } 0045 0046 qCDebug(KSTARS_INDI) << "Received new device" << dp.getDeviceName(); 0047 0048 // First iteration find unique matches 0049 for (auto &oneDriverInfo : m_ManagedDrivers) 0050 { 0051 if (oneDriverInfo->getUniqueLabel() == QString(dp.getDeviceName())) 0052 { 0053 oneDriverInfo->setUniqueLabel(dp.getDeviceName()); 0054 DeviceInfo *devInfo = new DeviceInfo(oneDriverInfo, dp); 0055 oneDriverInfo->addDevice(devInfo); 0056 emit newINDIDevice(devInfo); 0057 return; 0058 } 0059 } 0060 0061 // Second iteration find partial matches 0062 0063 for (auto &oneDriverInfo : m_ManagedDrivers) 0064 { 0065 auto dvName = oneDriverInfo->getName().split(' ').first(); 0066 if (dvName.isEmpty()) 0067 dvName = oneDriverInfo->getName(); 0068 if (/*dv->getUniqueLabel() == dp->getDeviceName() ||*/ 0069 QString(dp.getDeviceName()).startsWith(dvName, Qt::CaseInsensitive) || 0070 ((oneDriverInfo->getDriverSource() == HOST_SOURCE || oneDriverInfo->getDriverSource() == GENERATED_SOURCE))) 0071 { 0072 oneDriverInfo->setUniqueLabel(dp.getDeviceName()); 0073 DeviceInfo *devInfo = new DeviceInfo(oneDriverInfo, dp); 0074 oneDriverInfo->addDevice(devInfo); 0075 emit newINDIDevice(devInfo); 0076 return; 0077 } 0078 } 0079 } 0080 0081 void ClientManager::newProperty(INDI::Property property) 0082 { 0083 // Do not emit the signal if the server is disconnected or disconnecting (deadlock between signals) 0084 if (!isServerConnected()) 0085 { 0086 IDLog("Received new property %s for disconnected device %s, discarding\n", property.getName(), property.getDeviceName()); 0087 return; 0088 } 0089 0090 //IDLog("Received new property %s for device %s\n", prop->getName(), prop->getgetDeviceName()); 0091 emit newINDIProperty(property); 0092 } 0093 0094 void ClientManager::updateProperty(INDI::Property property) 0095 { 0096 emit updateINDIProperty(property); 0097 } 0098 0099 void ClientManager::removeProperty(INDI::Property prop) 0100 { 0101 const QString name = prop.getName(); 0102 const QString device = prop.getDeviceName(); 0103 emit removeINDIProperty(prop); 0104 0105 // If BLOB property is removed, remove its corresponding property if one exists. 0106 if (blobManagers.empty() == false && prop.getType() == INDI_BLOB && prop.getPermission() != IP_WO) 0107 emit removeBLOBManager(device, name); 0108 } 0109 0110 void ClientManager::processRemoveBLOBManager(const QString &device, const QString &property) 0111 { 0112 auto manager = std::find_if(blobManagers.begin(), blobManagers.end(), [device, property](auto & oneManager) 0113 { 0114 const auto bProperty = oneManager->property("property").toString(); 0115 const auto bDevice = oneManager->property("device").toString(); 0116 return (device == bDevice && property == bProperty); 0117 }); 0118 0119 if (manager != blobManagers.end()) 0120 { 0121 (*manager)->disconnectServer(); 0122 (*manager)->deleteLater(); 0123 blobManagers.removeOne(*manager); 0124 } 0125 } 0126 0127 void ClientManager::processNewProperty(INDI::Property prop) 0128 { 0129 // Only handle RW and RO BLOB properties 0130 if (prop.getType() == INDI_BLOB && prop.getPermission() != IP_WO) 0131 { 0132 BlobManager *bm = new BlobManager(this, getHost(), getPort(), prop.getDeviceName(), prop.getName()); 0133 connect(bm, &BlobManager::propertyUpdated, this, &ClientManager::updateINDIProperty); 0134 connect(bm, &BlobManager::connected, this, [prop, this]() 0135 { 0136 if (prop && prop.getRegistered()) 0137 emit newBLOBManager(prop.getDeviceName(), prop); 0138 }); 0139 blobManagers.append(bm); 0140 } 0141 } 0142 0143 void ClientManager::disconnectAll() 0144 { 0145 disconnectServer(); 0146 for (auto &oneManager : blobManagers) 0147 oneManager->disconnectServer(); 0148 } 0149 0150 void ClientManager::removeDevice(INDI::BaseDevice dp) 0151 { 0152 QString deviceName = dp.getDeviceName(); 0153 0154 QMutableListIterator<BlobManager*> it(blobManagers); 0155 while (it.hasNext()) 0156 { 0157 auto &oneManager = it.next(); 0158 if (oneManager->property("device").toString() == deviceName) 0159 { 0160 oneManager->disconnect(); 0161 it.remove(); 0162 } 0163 } 0164 0165 for (auto &driverInfo : m_ManagedDrivers) 0166 { 0167 for (auto &deviceInfo : driverInfo->getDevices()) 0168 { 0169 if (deviceInfo->getDeviceName() == deviceName) 0170 { 0171 qCDebug(KSTARS_INDI) << "Removing device" << deviceName; 0172 0173 emit removeINDIDevice(deviceName); 0174 0175 driverInfo->removeDevice(deviceInfo); 0176 0177 if (driverInfo->isEmpty()) 0178 { 0179 driverInfo->setClientState(false); 0180 m_ManagedDrivers.removeOne(driverInfo); 0181 } 0182 0183 return; 0184 } 0185 } 0186 } 0187 } 0188 0189 void ClientManager::newMessage(INDI::BaseDevice dp, int messageID) 0190 { 0191 emit newINDIMessage(dp, messageID); 0192 } 0193 0194 void ClientManager::newUniversalMessage(std::string message) 0195 { 0196 emit newINDIUniversalMessage(QString::fromStdString(message)); 0197 } 0198 0199 0200 void ClientManager::appendManagedDriver(const QSharedPointer<DriverInfo> &driver) 0201 { 0202 qCDebug(KSTARS_INDI) << "Adding managed driver" << driver->getName(); 0203 0204 m_ManagedDrivers.append(driver); 0205 0206 driver->setClientManager(this); 0207 0208 sManager = driver->getServerManager(); 0209 } 0210 0211 void ClientManager::removeManagedDriver(const QSharedPointer<DriverInfo> &driver) 0212 { 0213 if (m_ManagedDrivers.empty()) 0214 { 0215 qCDebug(KSTARS_INDI) << "removeManagedDriver: no managed drivers!"; 0216 return; 0217 } 0218 0219 qCDebug(KSTARS_INDI) << "Removing managed driver" << driver->getName(); 0220 0221 driver->setClientState(false); 0222 m_ManagedDrivers.removeOne(driver); 0223 0224 for (auto &di : driver->getDevices()) 0225 { 0226 // #1 Remove from GUI Manager 0227 GUIManager::Instance()->removeDevice(di->getDeviceName()); 0228 0229 // #2 Remove from INDI Listener 0230 INDIListener::Instance()->removeDevice(di->getDeviceName()); 0231 0232 // #3 Remove device from Driver Info 0233 driver->removeDevice(di); 0234 } 0235 } 0236 0237 void ClientManager::serverConnected() 0238 { 0239 qCDebug(KSTARS_INDI) << "INDI server connected."; 0240 0241 for (auto &oneDriverInfo : m_ManagedDrivers) 0242 { 0243 oneDriverInfo->setClientState(true); 0244 if (sManager) 0245 oneDriverInfo->setHostParameters(sManager->getHost(), sManager->getPort()); 0246 } 0247 0248 m_PendingConnection = false; 0249 m_ConnectionRetries = MAX_RETRIES; 0250 0251 emit started(); 0252 } 0253 0254 void ClientManager::serverDisconnected(int exitCode) 0255 { 0256 if (m_PendingConnection) 0257 qCDebug(KSTARS_INDI) << "INDI server connection refused."; 0258 else 0259 qCDebug(KSTARS_INDI) << "INDI server disconnected. Exit code:" << exitCode; 0260 0261 for (auto &oneDriverInfo : m_ManagedDrivers) 0262 { 0263 oneDriverInfo->setClientState(false); 0264 oneDriverInfo->reset(); 0265 } 0266 0267 if (m_PendingConnection) 0268 { 0269 // Should we retry again? 0270 if (m_ConnectionRetries-- > 0) 0271 { 0272 // Connect again in 1 second. 0273 QTimer::singleShot(1000, this, [this]() 0274 { 0275 qCDebug(KSTARS_INDI) << "Retrying connection again..."; 0276 if (connectServer() == false) 0277 serverDisconnected(0); 0278 else 0279 m_PendingConnection = false; 0280 }); 0281 } 0282 // Nope cannot connect to server. 0283 else 0284 { 0285 m_PendingConnection = false; 0286 m_ConnectionRetries = MAX_RETRIES; 0287 emit failed(i18n("Failed to connect to INDI server %1:%2", getHost(), getPort())); 0288 } 0289 } 0290 // Did server disconnect abnormally? 0291 else if (exitCode < 0) 0292 emit terminated(i18n("Connection to INDI host at %1 on port %2 lost. Server disconnected: %3", getHost(), getPort(), 0293 exitCode)); 0294 } 0295 0296 const QList<QSharedPointer<DriverInfo>> &ClientManager::getManagedDrivers() const 0297 { 0298 return m_ManagedDrivers; 0299 } 0300 0301 void ClientManager::establishConnection() 0302 { 0303 qCDebug(KSTARS_INDI) 0304 << "INDI: Connecting to local INDI server on port " << getPort() << " ..."; 0305 0306 m_PendingConnection = true; 0307 m_ConnectionRetries = 2; 0308 0309 if (connectServer() == false) 0310 serverDisconnected(0); 0311 else 0312 m_PendingConnection = false; 0313 } 0314 0315 const QSharedPointer<DriverInfo> &ClientManager::findDriverInfoByName(const QString &name) 0316 { 0317 auto pos = std::find_if(m_ManagedDrivers.begin(), m_ManagedDrivers.end(), [name](QSharedPointer<DriverInfo> oneDriverInfo) 0318 { 0319 return oneDriverInfo->getName() == name; 0320 }); 0321 0322 return *pos; 0323 } 0324 0325 const QSharedPointer<DriverInfo> &ClientManager::findDriverInfoByLabel(const QString &label) 0326 { 0327 auto pos = std::find_if(m_ManagedDrivers.begin(), m_ManagedDrivers.end(), [label](QSharedPointer<DriverInfo> oneDriverInfo) 0328 { 0329 return oneDriverInfo->getLabel() == label; 0330 }); 0331 0332 return *pos; 0333 } 0334 0335 void ClientManager::setBLOBEnabled(bool enabled, const QString &device, const QString &property) 0336 { 0337 for(auto &bm : blobManagers) 0338 { 0339 if (bm->property("device") == device && (property.isEmpty() || bm->property("property") == property)) 0340 { 0341 bm->setEnabled(enabled); 0342 return; 0343 } 0344 } 0345 } 0346 0347 bool ClientManager::isBLOBEnabled(const QString &device, const QString &property) 0348 { 0349 for(auto &bm : blobManagers) 0350 { 0351 if (bm->property("device") == device && bm->property("property") == property) 0352 return bm->property("enabled").toBool(); 0353 } 0354 0355 return false; 0356 }